package com.justdoit.facedemo.service;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.arcsoft.face.FaceFeature;
import com.arcsoft.face.FaceInfo;
import com.arcsoft.face.FaceSimilar;
import com.arcsoft.face.enums.CompareModel;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.justdoit.facedemo.base.Result;
import com.justdoit.facedemo.base.Results;
import com.justdoit.facedemo.domain.User;
import com.justdoit.facedemo.mapper.UserMapper;
import com.justdoit.facedemo.utils.ArcFaceUtils;
import com.justdoit.facedemo.utils.ArcFaceWorker;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import sun.misc.BASE64Decoder;

import java.io.IOException;
import java.util.List;
import java.util.Set;

@Service
@Slf4j
public class UserService extends ServiceImpl<UserMapper, User> {

    private final UserMapper userMapper;



    // redis
    private final StringRedisTemplate redisTemplate;

    // 人脸识别
    private final ArcFaceWorker faceWorker;

    public UserService(UserMapper userMapper, StringRedisTemplate redisTemplate, ArcFaceWorker faceWorker) {
        this.userMapper = userMapper;
        this.redisTemplate = redisTemplate;
        this.faceWorker = faceWorker;
    }

    //利用mybatis plus 提供的save方法来新增或者修改
    //新增用户或者修改用户
    public boolean saveUser(User user) {
        //新增或者修改用mybatis plus 提供的一个方法就可以了
        return saveOrUpdate(user);
    }


    public Result<Object> UserFace(User user) {
        // 使用图片处理类，进行处理图片，可以获得两个包装类：原始图片信息、二次包装图片信息
        ArcFaceUtils.ImageInfoMeta imageInfoMeta = ArcFaceUtils.packImageInfoMeta(user.getUserFaceFeature());
        // 调用人脸检测方法，传入二次包装类，返回人脸信息集合
        List<FaceInfo> faceInfos = faceWorker.detectFace(imageInfoMeta.getImageInfoEx());
        if (faceInfos.size()<1) return Results.newError("未识别到人脸，请重试");
        // 人脸特征提取，成功后获得人脸特征信息，失败为 null
        FaceFeature faceFeature = faceWorker.extractFaceFeature(faceInfos, imageInfoMeta.getImageInfoEx());

        // 如果不为null，则保存特征信息
        if (faceFeature != null) {
            // 将提取到的特征信息保存到数据库
            user.setUserFaceFeature(faceFeature.getFeatureData());
            // 判断保存结果
            if (userMapper.updateFace(user) == 1) {
                // 先看缓存中，有没有数据
                final Set<Object> faceTable = redisTemplate.opsForHash().keys("faceTable");
                // 判断缓存中，有没有人脸表
                if (!faceTable.isEmpty()) {
                    // 遍历循环
                    for (Object o : faceTable) {
                        String next = (String) o;
                        // 条件成立，表示缓存中存在，需要先进行移除，然后添加新的
                        if (next.equals(String.valueOf(user.getUserId()))) {
                            // 删除缓存中的指定人脸信息
                            redisTemplate.opsForHash().delete("faceTable", String.valueOf(user.getUserId()));
                            redisTemplate.opsForHash().put("faceTable", String.valueOf(user.getUserId()), JSON.toJSONString(user.getUserFaceFeature()));
                            user.setUserFaceFeature(null);
                            return Results.newSuccess(user);
                        }
                    }
                }
                // 否则直接添加
                redisTemplate.opsForHash().put("faceTable", String.valueOf(user.getUserId()), JSON.toJSONString(user.getUserFaceFeature()));
                user.setUserFaceFeature(null);
                return  Results.newSuccess(user);
            }
            return Results.newError("人脸保存失败，请稍后重试");
        }
        return Results.newError("未识别到人脸信息，请稍后重试");

    }


    public Result<User> selectFace(byte[] file) throws IOException {

        // 使用图片处理类，进行处理图片，可以获得两个包装类：原始图片信息、二次包装图片信息
        ArcFaceUtils.ImageInfoMeta imageInfoMeta = ArcFaceUtils.packImageInfoMeta(file);

        // 调用人脸检测方法，传入二次包装类，返回人脸信息集合
        List<FaceInfo> faceInfos = faceWorker.detectFace(imageInfoMeta.getImageInfoEx());

        // 人脸特征提取，成功后获得人脸特征信息，失败为 null
        FaceFeature faceFeature = faceWorker.extractFaceFeature(faceInfos, imageInfoMeta.getImageInfoEx());

        if (faceFeature != null) {
            // 从缓存中取出指定库中的所有 key
            Set<Object> faceTable = redisTemplate.opsForHash().keys("faceTable");

            // 遍历 key 并获取到缓存中，所有的人脸数据
            for (Object o : faceTable) {
                String UserId = (String) o;
                String faceData = (String) redisTemplate.opsForHash().get("faceTable", UserId);

                // 去除JSON前后缀
                assert faceData != null;
                faceData = StrUtil.unWrap(faceData, "\"", "\"");


                FaceFeature faceFeature1 = new FaceFeature();
                faceFeature1.setFeatureData(new BASE64Decoder().decodeBuffer(faceData));

                final FaceSimilar faceSimilar = faceWorker.compareFaceFeature(faceFeature,faceFeature1 , CompareModel.LIFE_PHOTO);
                if (faceSimilar.getScore() >= 0.72) {
                    User user = userMapper.selectById(Integer.valueOf(UserId));
                    // 去除人脸数据，影响美观
                    user.setUserFaceFeature(null);

                    // 成功返回人脸信息
                    return Results.newSuccess(user);
                }
            }
            return Results.newError("查无此人");
        }
        return Results.newError("未识别到人脸");
    }


    public Result<Object> login(String username, String password) {

        final QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.eq("user_account",username).eq("user_password",password);
        final User user = userMapper.selectOne(userQueryWrapper);
        return user==null? Results.newError("用户名或密码错误"):Results.newSuccess(user);
    }

    public Result<Object> register(String username, String password) {
        if (username!=null&&!username.isEmpty()&&password!=null&&!password.isEmpty()){
            final User user = new User();
            user.setUserAccount(username);
            user.setUserPassword(password);
            return  saveOrUpdate(user) ? Results.newFailedResult("200","注册成功"):Results.newError("注册失败，请稍后重试");
        }
        return Results.newError("用户名或密码不能为空");
    }
}